part of '../widgets.dart';



class VanRadio extends StatelessWidget {
  /// props - 选中值/标识符，通常为一个唯一的字符串或数字
  final dynamic value;

  /// props - 未选中值 - 使用[VanRadioGroup]无效
  final dynamic uncheckValue;

  /// props - 是否选中
  final bool? checked;

  /// props - 控制器
  final VanCheckedController? controller;

  /// props - 形状，可选值为 square dot(默认: round)
  final VanRadioShape? shape;

  /// props - 是否为禁用状态(默认: false)
  final bool? disabled;

  /// props - 是否禁用文本内容点击(默认: false)
  final bool labelDisabled;

  /// props - 文本位置，可选值为 left(默认: right)
  final VanRadioPosition labelPosition;

  /// props - 图标大小，默认单位为 px(默认: 20px)
  final double? iconSize;

  /// props - 选中状态颜色(默认: #1989fa)
  final Color? checkedColor;

  final VanRadioStyle? style;

  /// events - 当绑定值变化时触发的事件 回调参数(value) - 使用[VanRadioGroup]无效
  final Function(dynamic)? onChange;

  /// events - 点击单选框时触发
  final VoidCallback? onClick;

  /// props - [String]标签文本 <br>
  /// slots - [VanRadioBuilder] or [Widget]自定义文本 <br>
  final dynamic child;

  /// slots - [VanRadioBuilder] or [Widget]自定义图标 <br>
  final dynamic icon;

  const VanRadio({
    super.key,
    this.value = true,
    this.uncheckValue = false,
    this.checked,
    this.controller,
    this.shape,
    this.disabled,
    this.labelDisabled = false,
    this.labelPosition = VanRadioPosition.right,
    this.iconSize,
    this.checkedColor,
    this.style,
    this.onChange,
    this.onClick,
    this.child,
    this.icon,
  });

  VanRadioStyle getComputedStyle(BuildContext context, {bool checked = false}) {
    if (style?.isNonNull == true) return style!;
    double? iconSize = style?.iconSize;
    Color? iconColor = style?.iconColor;
    double? duration = style?.duration;
    double? labelMargin = style?.labelMargin;
    Color? labelColor = style?.labelColor;

    final group = VanProvider.of<VanRadioGroup>(context);

    final disabled = this.disabled ?? group?.disabled ?? false;

    if (disabled) {
      iconColor ??= kVanRadioDisabledIconColor.toColor(context);
      labelColor ??= kVanRadioDisabledLabelColor.toColor(context);
    } else if (checked) {
      iconColor ??= checkedColor ?? group?.checkedColor;
      iconColor ??= kVanRadioCheckedIconColor.toColor(context);
    }

    iconSize ??= kVanRadioIconSize.toDouble(context);
    iconColor ??= kVanRadioIconColor.toColor(context);
    duration ??= kVanRadioDuration.toDouble(context);
    labelMargin ??= kVanRadioLabelMargin.toDouble(context);
    labelColor ??= kVanRadioLabelColor.toColor(context);

    return VanRadioStyle(
      iconSize: iconSize,
      iconColor: iconColor,
      duration: duration,
      labelMargin: labelMargin,
      labelColor: labelColor,
    );
  }

  @override
  Widget build(BuildContext context) {
    VanRadioShape? shape = this.shape;
    bool? checked = this.checked;
    bool? disabled = this.disabled;
    final group = VanProvider.of<VanRadioGroup>(context);
    shape ??= group?.shape;
    disabled ??= group?.disabled;

    shape ??= VanRadioShape.round;
    checked ??= false;
    disabled ??= false;

    VanCheckedController? controller = this.controller;

    if (group?.controller != null) {
      controller ??= _VanRadioCheckedController(
        controller: group?.controller,
        value: value,
        checked: checked,
      );
    }
    controller ??= VanCheckedController(checked);

    GestureTapCallback? onTap;

    return ValueListenableBuilder(
      valueListenable: controller,
      builder: (ctx, checked, child) {
        final style = getComputedStyle(context, checked: checked);
        if (disabled == false) {
          onTap = () {
            if (group?.controller != null) {
              group!.controller.value = value;
            } else {
              controller!.value = !checked;
              if (onChange != null) {
                onChange!(controller.value ? value : uncheckValue);
              }
            }
            if (onClick != null) onClick!();
          };
        }

        Widget icon;
        if (this.icon is Widget) {
          icon = this.icon;
        } else if (this.icon is VanRadioBuilder) {
          icon = this.icon!(VanRadioScope(checked: checked, disabled: disabled!));
        } else {
          if (this.icon != null) {
            _logger.e(ArgumentError("VanRadio.icon only type support [Widget] or [VanRadioBuilder]", "icon"));
          }
          IconData iconData;
          if (shape == VanRadioShape.dot) {
            iconData = iconData = checked ? Icons.radio_button_checked_rounded : Icons.radio_button_unchecked_rounded;
          } else if (shape == VanRadioShape.square) {
            iconData = iconData = checked ? Icons.check_box_rounded : Icons.check_box_outline_blank_rounded;
          } else {
            iconData = iconData = checked ? Icons.check_circle_rounded : Icons.radio_button_unchecked_rounded;
          }
          icon = Icon(iconData);
        }

        final iconThemeData = Theme.of(context).iconTheme.copyWith(size: style.iconSize, color: style.iconColor);
        icon = IconTheme(data: iconThemeData, child: icon);

        if (disabled == false && labelDisabled) {
          icon = GestureDetector(onTap: onTap, child: icon);
        }

        Widget? label;
        if (this.child is String) {
          if (this.child.isNotEmpty) label = Text(this.child!);
        } else if (this.child is Widget) {
          label = this.child;
        } else if (this.child is VanRadioBuilder) {
          label = this.child!(VanRadioScope(checked: checked, disabled: disabled!));
        } else {
          if (this.child != null) {
            _logger.e("VanRadio.child only type support [String] or [Widget] or [VanRadioBuilder]");
          }
        }

        Widget widget;
        if (label != null) {
          label = DefaultTextStyle(
            style: TextStyle(color: style.labelColor),
            child: label,
          );
          List<Widget> ws = [icon, SizedBox(width: style.labelMargin), label];
          if (labelPosition == VanRadioPosition.left) ws = ws.reversed.toList();
          widget = Row(children: ws);
        } else {
          widget = icon;
        }

        if (disabled == false && !labelDisabled) {
          widget = GestureDetector(onTap: onTap, child: widget);
        }

        if (group != null && group.children?.lastOrNull != this) {
          if (group.direction == VanRadioDirection.horizontal) {
            widget = Padding(
              padding: EdgeInsets.only(right: style.labelMargin ?? 0),
              child: widget,
            );
          } else {
            widget = Padding(
              padding: EdgeInsets.only(bottom: (style.labelMargin ?? 0) / 2),
              child: widget,
            );
          }
        }

        return widget;
      },
    );
  }
}

class _VanRadioCheckedController extends VanCheckedController {
  final VanCtrl? controller;
  late final VoidCallback? listener;
  final dynamic original;

  _VanRadioCheckedController._raw(super.value, {this.controller, this.original}) {
    if (controller != null) {
      listener = () => value = controller!.value == original && original != null;
      controller!.addListener(listener!);
    }
  }

  factory _VanRadioCheckedController({VanCtrl? controller, bool? checked, dynamic value}) {
    bool? state;
    if (controller != null) {
      state = value != null && controller.value == value;
    } else {
      state = checked;
    }
    return _VanRadioCheckedController._raw(state ?? false, controller: controller, original: value);
  }

  @override
  void dispose() {
    if (listener != null && controller != null) {
      controller!.removeListener(listener!);
    }
    super.dispose();
  }
}

enum VanRadioShape { round, square, dot }

enum VanRadioPosition { left, right }

enum VanRadioDirection { horizontal, vertical }

class VanRadioScope {
  final bool checked;
  final bool disabled;

  VanRadioScope({required this.checked, required this.disabled});
}

typedef VanRadioBuilder = Widget Function(VanRadioScope scope);
